package com.example.security;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTException;
import cn.hutool.jwt.JWTUtil;
import com.example.util.JwtUtil;
import com.example.util.Result;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.*;

import static com.example.util.JwtUtil.SECRET_KEY;

@Slf4j
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                  HttpServletResponse response,
                                  FilterChain filterChain)
            throws ServletException, IOException {

        log.info("JwtAuthenticationFilter: doFilterInternal");

        // 1. 放行OPTIONS请求
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            filterChain.doFilter(request, response);
            return;
        }

        // 2. 获取Token
        String authHeader = request.getHeader("Authorization");
        if (StrUtil.isBlank(authHeader) || !authHeader.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }

        log.info("authHeader: {}", authHeader);

        try {
            String token = authHeader.substring(7);

            log.info("token: {}", token);

            // 3. 验证Token
            JWT jwt = JWTUtil.parseToken(token);
            log.info("jwt: {}", jwt);
            log.info("jwt is expired: {}", JWT.of(token).setKey(SECRET_KEY).verify());
            if (!JwtUtil.verifyToken(token)) {
                sendError(response, 401, "Token验证失败");
                return;
            }
            JSONObject loginUser = (JSONObject) jwt.getPayload("loginUser");
            log.info("loginUser: {}", loginUser);
            // 类型安全地获取属性
            Long id = loginUser.getLong("id");
            String username = loginUser.getStr("username");
            Integer role = loginUser.getInt("role");
            List<String> permissions = loginUser.get("permissions", List.class);
            List<SimpleGrantedAuthority> authorities = (List<SimpleGrantedAuthority>) getAuthorities(permissions).stream().toList();
            log.info("id: {}, username: {}, role: {}, status: {}, permissions: {}, authorities: {}", id, username, role, permissions, authorities);

            // 4. 创建LoginUser对象
            LoginUser user = new LoginUser(id, username, role, permissions, authorities);
            // 5. 创建Authentication对象
            UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(user,  null,authorities);

            // 6. 设置到SecurityContext
            SecurityContextHolder.getContext().setAuthentication(authentication);

            filterChain.doFilter(request, response);

        } catch (JWTException e) {
            sendError(response, 401, "Token解析失败");
        } catch (Exception e) {
            sendError(response, 500, "服务器内部错误");
        }
    }

    private void sendError(HttpServletResponse response, int code, String msg) throws IOException {
        response.setStatus(code);
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(JSONUtil.toJsonStr(Result.error(code, msg)));
    }


    private Collection<? extends GrantedAuthority> getAuthorities(List<String> permissions) {
        List<SimpleGrantedAuthority> authorities = null;
        //把permissions中String类型的权限信息封装成SimpleGrantedAuthority对象
        authorities = new ArrayList<>();
        for (String permission : permissions) {
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + permission);
            authorities.add(authority);
        }
        return authorities;
    }
}